package com.baiyun.stock.service.Impl;

import com.baiyun.stock.config.StockInfoConfig;
import com.baiyun.stock.constant.ParseType;
import com.baiyun.stock.mapper.StockBusinessMapper;
import com.baiyun.stock.mapper.StockMarketIndexInfoMapper;
import com.baiyun.stock.mapper.StockRtInfoMapper;
import com.baiyun.stock.pojo.entity.StockMarketIndexInfo;
import com.baiyun.stock.pojo.entity.StockRtInfo;
import com.baiyun.stock.service.StockTimerTaskService;
import com.baiyun.stock.utils.DateTimeUtil;
import com.baiyun.stock.utils.IdWorker;
import com.baiyun.stock.utils.ParserStockInfoUtil;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


@Service
@Slf4j
@RequiredArgsConstructor
public class StockTimerTaskServiceImpl implements StockTimerTaskService {

    private final RestTemplate restTemplate;
    private final RabbitTemplate rabbitTemplate;
    private final StockInfoConfig stockInfoConfig;
    private final IdWorker idWorker;
    private final StockMarketIndexInfoMapper stockMarketIndexInfoMapper;
    private final ParserStockInfoUtil parserStockInfoUtil;
    private final StockBusinessMapper stockBusinessMapper;
    private final StockRtInfoMapper stockRtInfoMapper;

    @Override
    public void getInnerMarketInfo() {
        //采集原始的大盘数据
        HttpHeaders httpHeaders = new HttpHeaders();
        String marketUrl = stockInfoConfig.getMarketUrl();
        StringBuilder sb = new StringBuilder();

        String url = sb.append(marketUrl + String.join(",", stockInfoConfig.getInner())).toString();

        httpHeaders.add("Referer","https://finance.sina.com.cn/stock/");
        httpHeaders.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36");

        HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);

        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);

        String marketInfo = response.getBody();
        log.info("获取大盘数据成功：{}", marketInfo);
        //正则表达式解析数据
        String reg="var hq_str_(.+)=\"(.+)\";";
        //编译表达式,获取编译对象
        Pattern pattern = Pattern.compile(reg);
        //匹配字符串
        Matcher matcher = pattern.matcher(marketInfo);
        ArrayList<StockMarketIndexInfo> list = new ArrayList<>();
        //判断是否有匹配的数值
        while (matcher.find()){
            //获取大盘的code
            String marketCode = matcher.group(1);
            //获取其它信息，字符串以逗号间隔
            String otherInfo=matcher.group(2);
            //以逗号切割字符串，形成数组
            String[] splitArr = otherInfo.split(",");
            //大盘名称
            String marketName=splitArr[0];
            //获取当前大盘的开盘点数
            BigDecimal openPoint=new BigDecimal(splitArr[1]);
            //前收盘点
            BigDecimal preClosePoint=new BigDecimal(splitArr[2]);
            //获取大盘的当前点数
            BigDecimal curPoint=new BigDecimal(splitArr[3]);
            //获取大盘最高点
            BigDecimal maxPoint=new BigDecimal(splitArr[4]);
            //获取大盘的最低点
            BigDecimal minPoint=new BigDecimal(splitArr[5]);
            //获取成交量
            Long tradeAmt=Long.valueOf(splitArr[8]);
            //获取成交金额
            BigDecimal tradeVol=new BigDecimal(splitArr[9]);
            //时间
            Date curTime = DateTimeUtil.getDateTimeWithoutSecond(splitArr[30] + " " + splitArr[31]).toDate();
            //组装entity对象
            StockMarketIndexInfo info = StockMarketIndexInfo.builder()
                    .id(idWorker.nextId())
                    .marketCode(marketCode)
                    .marketName(marketName)
                    .curPoint(curPoint)
                    .openPoint(openPoint)
                    .preClosePoint(preClosePoint)
                    .maxPoint(maxPoint)
                    .minPoint(minPoint)
                    .tradeVolume(tradeVol)
                    .tradeAmount(tradeAmt)
                    .curTime(curTime)
                    .build();
            //收集封装的对象，方便批量插入
            list.add(info);
        }
        //批量插入
        int count = stockMarketIndexInfoMapper.insertBatch(list);
        if (count > 0){
            // 大盘数据采集完毕后，通知backend工程刷新缓存
            // 向交换机发送消息
            rabbitTemplate.convertAndSend("stockExchange","inner.market",new Date());
            log.info("批量插入成功");
        }else {
            log.error("批量插入失败");
        }
        log.info("批量插入了：{}条数据",count);
    }


    /**
     * 获取当日个股的详细信息
     */
    @Override
    public void getStockRtIndex() {
        //获取原始js数据
        //批量获取股票ID集合
        List<String> stockIds = stockBusinessMapper.getStockIds();
        //计算出符合sina命名规范的股票id数据
        stockIds = stockIds.stream().map(id -> {
            return id.startsWith("6") ? "sh" + id : "sz" + id;
        }).collect(Collectors.toList());
        //设置公共请求头对象
        //设置请求头数据
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer", "https://finance.sina.com.cn/stock/");
        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) " +
                "Chrome/72.0.3626.121 Safari/537.36");
        HttpEntity<String> entity = new HttpEntity<>(headers);
        //一次性查询过多，我们将需要查询的数据先进行分片处理，每次最多查询20条股票数据
        Lists.partition(stockIds, 10).forEach(list -> {
            //拼接股票url地址
            String stockUrl = stockInfoConfig.getMarketUrl() + String.join(",", list);
            //获取响应数据
            String result = restTemplate.postForObject(stockUrl, entity, String.class);
            List<StockRtInfo> infos = parserStockInfoUtil.parser4StockOrMarketInfo(result, ParseType.ASHARE);
            log.info("数据量：{}", infos.size());
            //批量插入
            int count = stockRtInfoMapper.insertBatch(infos);
            log.info("批量插入了：{}条数据",count);

        });
    }
}
